﻿
#ifndef MOTIONCONTROLLER_H
#define MOTIONCONTROLLER_H

#include <QObject>
#include <QSet>
#include <QPair>
#include <QTimer>

/// 运动控制卡的纯虚接口，规范了运动控制卡的几种基本功能。
/// 不同厂家的运动控制卡的功能有所不同，但是有些基本功能是各个运动控制卡都应该具备的，这个类就是将这些基本功能抽象出来。
/// 运动控制卡的功能包括几大类：
/// （1）轴运动类，单轴运动，多轴运动，点动、直线插补等
/// （2）设定运动速度、加速度等
/// （3）回零
/// （4）IO ，大多数运动控制卡都具有一些 IO。
/// （5）限位状态反馈，零点状态反馈，报警信号等。
///
/// 所有不支持的功能，函数返回值为 false. 同时将 m_errno 设置为 MTCTR_NOT_SUPPORT
/// 可以输出几个信号：goHomeFinished、limitReached、axisStoped、INPortChanged、positionChanged、lineMoveStoped
///

///定义一些常见的错误代码， 0 - 99 为通用的错误代码。派生类额外的错误代码建议从 100 开始定义。
#define MTCTR_NOERR        0
#define MTCTR_TIMEOUT      1
#define MTCTR_BAD_CMD      2
#define MTCTR_UNKNOWN      3
#define MTCTR_UNREACHABLE  4
#define MTCTR_BITNO        5
#define MTCTR_AXIS_NO      6
#define MTCTR_NOT_SUPPORT  7

class MotionController : public QObject
{
    Q_OBJECT
public:
    MotionController(QObject *parent = 0);

    /**
     * @brief errCode 返回错误代码。某个操作返回 false 后，可以通过读取错误代码知道具体的错误原因。
     * @return
     */
    virtual int errCode();

    /**
     * @brief isValid 检查控制卡当前是否可用。
     * @return false 表示不可用，通常是还没有连接运动控制卡，或者运动控制卡掉线
     */
    virtual bool isValid() {m_errno = MTCTR_UNKNOWN; return false;}

    /**
     * @brief axisCount 返回当前运动控制卡支持几个轴。
     * @param count 支持的轴数
     * @return
     */
    virtual bool axisCount(int &count);

    /**
     * @brief init  初始化运动控制卡
     */
    virtual void init() = 0;

public slots:
/// 速度相关
    /**
     *  \brief 设置电机运行速度
     *  \param [in] axis 指定轴
     *  \param [in] speed 轴的运动速度，单位 Hz
     */
    virtual bool setSpeed(unsigned short axis, int speed) = 0;

    /**
     * @brief setHomeSpeed 设置回零的速度
     * @param axis  轴号，从 0 开始
     * @param speed 回零速度
     * @return
     */
    virtual bool setHomeSpeed(unsigned short axis, int speed) = 0;

    /**
     * @brief setAcceleration 设置电机的运行加速度
     * @param axis 轴号，从 0 开始
     * @param acceleration 轴的运动加速度
     */
    virtual bool setAcceleration(unsigned short axis, int acceleration) = 0;

    /**
     * @brief setDeceleration 设置电机停止前的减速度
     * @param axis 轴号，从 0 开始
     * @param deceleration 轴的运动减速度
     */
    virtual bool setDeceleration(unsigned short axis, int deceleration) = 0;

    /**
     * @brief setSpeed 设置电机的速度
     * @param axis 轴号，从 0 开始
     * @param start_speed 起始速度，有些控制卡不支持这个参数，自动忽略
     * @param max_speed 最高速度，也就是目标速度
     * @param tacc 加速度
     * @param tdec 减速度
     * @param stop_speed  停止速度，减速停止时，减速到这个速度后就直接停止。有些控制卡不支持这个参数，自动忽略
     * @return
     */
    virtual bool setSpeed2(unsigned short axis, int start_speed, int max_speed, double tacc, double tdec, int stop_speed);

    /**
     * @brief setHomeSpeed 设置回原点时的速度 设置回原定的速度
     * @param axis 轴号，从 0 开始
     * @param start_speed 起始速度，有些控制卡不支持这个参数，自动忽略
     * @param max_speed  最高速度，也就是目标速度
     * @param tacc 加速度
     * @param tdec 减速度
     * @param stop_speed 停止速度，减速停止时，减速到这个速度后就直接停止。有些控制卡不支持这个参数，自动忽略
     * @return
     */
    virtual bool setHomeSpeed2(unsigned short axis, int start_speed, int max_speed, double tacc, double tdec, int stop_speed);

    /**
     * @brief setStartSpeed 设置起跳速度
     * @param axis 轴号，从 0 开始
     * @param startSpeed 起始速度，有些控制卡不支持这个参数，自动忽略
     */
    virtual bool setStartSpeed(unsigned short axis, int startSpeed);

    /**
     * @brief setStopSpeed 设置停止前的最后速度
     * @param axis 轴号，从 0 开始
     * @param stopSpeed 停止速度，减速停止时，减速到这个速度后就直接停止。有些控制卡不支持这个参数，自动忽略
     */
    virtual bool setStopSpeed(unsigned short axis, int stopSpeed);

/// 运动相关
    virtual bool home(unsigned short axis) = 0;
    virtual bool goHome(unsigned short axis, int speed);
    /**
     *  \brief 运动电机到指定位置
     *  \param [in] axis 轴号，从 0 开始
     *  \param [in] position 要运动到的位置，对应控制卡内部脉冲计数
     */
    virtual bool moveTo(unsigned short axis, int position) = 0;

    /**
     *  \brief 使得电机朝某个指定方向运动, JOG 运动
     *  \param [in] axis 轴号，从 0 开始
     *  \param [in] dir 要运动的方向，1 表示正转，-1 表示反转
     */
    virtual bool move(unsigned short axis, int dir = 1) = 0;

    /**
     *  \brief 电机转动 steps 步
     *  \param [in] axis 指定要运动的轴
     *  \param [in] steps 转动的步数，大于 0 表示正转，小于 0 表示反转
     */
    virtual bool moveSteps(unsigned short axis, int steps) = 0;

//// 插补函数
    virtual bool moveXYSteps(int stepX, int stepY, int spd) = 0;
    /**
     * @brief stop 停止电机运动
     * @param axis 指定轴
     */
    virtual bool stopAxis(unsigned short axis) = 0;

    /**
     * @brief stop 停止所有轴的运动。通常会有减速过程。
     * @return
     */
    virtual bool stop() = 0;

    /**
     * @brief abort 急停，停止所有轴的运动。通常是直接停止输出脉冲。也就是急停。
     */
    virtual bool abort() = 0;

public:
//// 位置相关
    /**
     *  \brief 读取控制卡内部电机步数计数器的数值
     *  \param [in] axis 指定轴
     *  \return 计数器的数值
     */
    virtual bool readTheoryPos(unsigned short axis, int32_t &value) = 0;

    /**
     * @brief readTheoryPosAll 读取控制卡内部电机步数计数器的数值
     * @param value 返回所有轴的数值
     */
    virtual bool readTheoryPosAll(int32_t value[]) = 0;
    /**
     *  \brief 读取控制卡内部编码器反馈计数器的数值
     *  \param [in] axis 指定轴
     *  \return 计数器的数值
     */
    virtual bool readEncoderPos(unsigned short axis, int32_t &value) = 0;

    /**
     * @brief readEncodePosAll 读取控制卡内部编码器反馈计数器的数值
     * @param value 返回所有轴的数值
     */
    virtual bool readEncoderPosAll(int32_t value[]) = 0;

public slots:
    /**
     * @brief setTheoryPos 设置控制卡内部电机步数计数器的计数值
     * @param axis
     * @param offset
     */
    virtual bool setTheoryPos(unsigned short axis, int32_t offset) = 0;

    /**
     * @brief setEncoderPos 设置控制卡内部编码器计数器的计数值
     * @param axis
     * @param offset
     */
    virtual bool setEncoderPos(unsigned short axis, int32_t offset) = 0;

public:
    /// 运动状态相关接口
    /**
     * @brief isMoving 判断一个轴是否在运动
     * @param axis
     * @param state true 表示正在运动中, false 表示没有在运动
     * @return false 表示调用失败，true 表示成功
     */
    virtual bool isMoving(unsigned short axis, bool& state) = 0;

    /**
     * @brief isReverseLimit 是否到限位
     * @param axis
     * @param state true 表示到限位，false 则没有到限位
     * @return
     */
    virtual bool isReverseLimit(unsigned short axis, bool& state) = 0;
    virtual bool isForwardLimit(unsigned short axis, bool& state) = 0;
    virtual bool isHome(unsigned short axis, bool& state)  = 0;
    virtual bool isEMStop(bool &state) = 0; //是否有急停信号
    virtual bool readLimitStatus(unsigned short axis, bool &llimit, bool &rlimit, bool &home);
    virtual bool readAxisEMStop(bool emstop[]) = 0; // 读取所有轴的急停信号


    /// IO 相关的接口，不是每个运动控制器都支持
    virtual bool readIOBit(int bitNo, bool &value) = 0;
    virtual bool readIOPort(int port, uint32_t &value) = 0;
    virtual bool writeIOBit(int bitNo, bool value) = 0;
    virtual bool writeIOPort(int port, uint32_t value) = 0;
    virtual bool setPWMOut(int channel, double freq, double duty);
    virtual bool PWMValue(int channel, double &freq, double &duty);

    /// 设置软限位
    virtual bool setSoftLlimit(unsigned short axis, int32_t llimit) = 0;
    virtual bool setSoftRlimit(unsigned short axis, int32_t rlimit) = 0;

    virtual bool action1() = 0;
    virtual bool action2() = 0;
signals:
    void goHomeFinished(unsigned short axis);
    void axisStoped(unsigned short axis, uint8_t reason);
    void lineMoveStoped(unsigned short coor);
    void limitStatusChanged(unsigned short axis, bool llimit, bool rlimit, bool home);
    void alarmReached(unsigned short axis, bool alarm, bool emstop);
    void INPortChanged(int port, uint32_t value); // 一个 PORT 最多支持 32个 IN IO
    void positionChanged(int32_t theoryPos[8], int32_t encoderPos[8]);
protected:

    QTimer *m_pTimer;
    int m_errno;

};

#endif // MOTIONCONTROLLER_H
